package com.zzyl.nursing.service.impl.member;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ServiceCapability;
import com.huaweicloud.sdk.iotda.v5.model.ServiceProperty;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowProductResponse;
import com.zzyl.common.core.domain.model.LoginUser;
import com.zzyl.common.utils.ServletUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.nursing.domain.Bed;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.Elder;
import com.zzyl.nursing.domain.menber.FamilyMember;
import com.zzyl.nursing.domain.menber.FamilyMemberElder;
import com.zzyl.nursing.dto.iot.IotMsgNotifyData;
import com.zzyl.nursing.dto.member.AddFamilyDto;
import com.zzyl.nursing.dto.member.DeviceDataByDayDto;
import com.zzyl.nursing.dto.member.QueryDevicePropertyDto;
import com.zzyl.nursing.dto.member.UserLoginRequestDto;
import com.zzyl.nursing.mapper.BedMapper;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.mapper.member.FamilyMemberElderMapper;
import com.zzyl.nursing.mapper.member.FamilyMemberMapper;
import com.zzyl.nursing.service.IElderService;
import com.zzyl.nursing.service.member.IFamilyMemberElderService;
import com.zzyl.nursing.service.member.IFamilyMemberService;
import com.zzyl.nursing.service.member.WechatService;
import com.zzyl.nursing.util.DeviceDataStatisticsUtils;
import com.zzyl.nursing.vo.member.*;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import com.zzyl.framework.web.service.TokenService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.zzyl.nursing.util.DeviceDataStatisticsUtils.convertToDayFloor;

@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService
{

    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private IFamilyMemberElderService familyMemberElderService;

    /**
     * 查询老人家属
     *
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return familyMemberMapper.selectById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return familyMemberMapper.insert(familyMember);
    }

    /**
     * 修改老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return familyMemberMapper.updateById(familyMember);
    }

    /**
     * 批量删除老人家属
     *
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return familyMemberMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除老人家属信息
     *
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return familyMemberMapper.deleteById(id);
    }

    /**
     * 小组实战：小程序1--绑定家人
     */
    @Autowired
    private IElderService elderService;
    @Override
    public void add(@RequestBody AddFamilyDto dto) {
        //拿到当前登录用户的userId
        Long userId = UserThreadLocal.getUserId();
        //1. 首先校验，查询elder表，是否有此数据
        LambdaQueryWrapper<Elder> lqw = new LambdaQueryWrapper<>();
        Elder elder = elderService.lambdaQuery().eq(Elder::getIdCardNo, dto.getIdCard()).one();
        if(elder == null){
            throw new RuntimeException("未找到此老人信息");
        }
        //2. 判断当前用户是否已经绑定了此老人
        Long count = familyMemberElderService.lambdaQuery().eq(FamilyMemberElder::getFamilyMemberId, userId)
                .eq(FamilyMemberElder::getElderId, elder.getId()).count();
        if(count > 0){
            throw new RuntimeException("不可重复绑定");
        }
        //3. 绑定
        FamilyMemberElder res = new FamilyMemberElder();
        res.setFamilyMemberId(userId);
        res.setElderId(elder.getId());
        res.setRemark(dto.getRemark());
        familyMemberElderService.save(res);
    }

    /**
     * 小组实战：小程序2--查询家人列表
     */
    @Override
    public List<MyFamilyVo> my() {
        Long userId = UserThreadLocal.getUserId();
        List<MyFamilyVo> list = familyMemberMapper.my(userId);
        return list;
    }


    /**
     * 小组实战：小程序3--查看家人列表（分页查询）
     */
    @Override
    public Page<FamilyPageVo> listByPage(Integer pageNum, Integer pageSize) {
        //手动分页
        PageHelper.startPage(pageNum, pageSize);
        Long userId = UserThreadLocal.getUserId();
        //这里只查询当前登录用户的家人
        List<FamilyPageVo> list = familyMemberMapper.listByPage(userId);
        Page page = (Page)list;
        return page;
    }

    /**
     * 小组实战： 小程序4-- 查询健康数据
     */
    @Autowired
    RedisTemplate<String, String> redisTemplate;
    @Autowired
    private IoTDAClient client;
    @Override
    public DeviceStatusResponseVo queryDeviceProperty(QueryDevicePropertyDto dto) {
        //1. 直接从redis中获取实时的设备数据
        String jsonStr = redisTemplate.opsForValue().get("iot:"+dto.getDeviceName());
        if(jsonStr == null){
            throw new RuntimeException("未查询到数据");
        }
        IotMsgNotifyData iotMsgNotifyData = JSONUtil.toBean(jsonStr, IotMsgNotifyData.class);
        //2. 解析Redis中的设备实时数据
        String eventTime = iotMsgNotifyData.getBody().getServices().get(0).getEventTime();
        String temp = parseIso8601ToTimestamp(eventTime);
        Map<String, Object> properties = iotMsgNotifyData.getBody().getServices().get(0).getProperties();
        PropertyStatusInfoVo propertyStatusInfoVo = new PropertyStatusInfoVo();
        //3. 从华为云查询产品属性
        ShowProductRequest request = new ShowProductRequest();
        request.withProductId(dto.getProductKey());
        ShowProductResponse response = client.showProduct(request);
        List<ServiceProperty> productProperties = response.getServiceCapabilities().get(0).getProperties();
        //4. 合并设备数据以及产品属性，封装返回
        properties.forEach((key, value) -> {
            DevicePropertyVo devicePropertyVo = new DevicePropertyVo();
            devicePropertyVo.setTime(temp);
            devicePropertyVo.setIdentifier(key);
            devicePropertyVo.setValue(value.toString());
            //补全产品属性信息
            for (ServiceProperty sp : productProperties) {
                if (sp.getPropertyName().equals(key)){
                    devicePropertyVo.setName(sp.getPropertyName());
                    devicePropertyVo.setDataType(sp.getDataType());
                    devicePropertyVo.setUnit(sp.getUnit());
                }
            }
            propertyStatusInfoVo.add(devicePropertyVo);
        });

        DeviceStatusResponseVo deviceStatusResponseVo = new DeviceStatusResponseVo(propertyStatusInfoVo);
        return deviceStatusResponseVo;
    }

    /**
     * 小组实战： 小程序5-- 按天统计查询指标数据
     */
    @Override
    public List<DeviceDataByDayVo> queryDeviceDataListByDay(DeviceDataByDayDto dto) {
        //思路是,通过device_data表中的remark字段，查询自己需要的物模型数据
        // 1. 解析前端传入的毫秒时间戳
        LocalDateTime start = DeviceDataStatisticsUtils.convertToHourFloor(dto.getStartTime());
        LocalDateTime end = DeviceDataStatisticsUtils.convertToHourFloor(dto.getEndTime());
        //2. 查询数据库
        List<DeviceDataByDayVo> list =  deviceDataMapper.queryDeviceDataListByDay(dto.getFunctionId(), dto.getIotId(),start, end);
        //3. 补全缺失小时为 0.0
        return DeviceDataStatisticsUtils.fillMissingHours(start, end, list);

    }

    /**
     * 小组实战： 小程序6-- 按周统计查询指标数据
     */
    @Override
    public List<DeviceDataByDayVo> queryDeviceDataListByWeek(DeviceDataByDayDto dto) {
        LocalDateTime start = convertToDayFloor(dto.getStartTime());
        LocalDateTime end = convertToDayFloor(dto.getEndTime());

        // 查询数据库获取每天平均数据
        List<DeviceDataByDayVo> dailyData = deviceDataMapper.queryDeviceDataListByWeek(
                dto.getFunctionId(), dto.getIotId(), start, end);

        // 填充缺失日期数据并转换格式
        return DeviceDataStatisticsUtils.fillMissingDaysWithFormat(start, end, dailyData);
    }



    /**
     * 微信登录
     *
     * @param dto
     * @return
     */
    @Autowired
    private WechatService wechatService;
    @Autowired
    private TokenService tokenService;

    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of("生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );


    public LoginVo login(UserLoginRequestDto dto) {
        //1.根据code调用微信api获取apenId
        String openid = wechatService.getOpenid(dto.getCode());
        //2.根据openId查询数据库获取用户信息family_member表
        LambdaQueryWrapper<FamilyMember> lqw = new LambdaQueryWrapper<>();
        lqw.eq(FamilyMember::getOpenId, openid);
        FamilyMember one = getOne(lqw);
        //4.调用微信api获取用户绑定手机号
        String phone = wechatService.getPhone(dto.getPhoneCode());

        //3.判断用户信息是否存在，如果不存在，则准备新增，设置openid
        if (one == null){
            //不存在，准备新建一个用户对象进行新增，有就不用操作
            one = new FamilyMember();
            //将得到的openid设置到用户对象中
            one.setOpenId(openid);
            String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                    + StringUtils.substring(phone, 7);
            one.setName(nickName);
        }
        one.setPhone(phone);


        //5.新增或者修改family_member表数据
        saveOrUpdate(one);
        //6.将用户id存入token中，并返回数据给前端
        Map<String,Object> claims = new HashMap<>();
        claims.put("nickName",one.getName());
        claims.put("userId",one.getId());
        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(one.getName());
        return loginVo;
    }

    //将UTC时间字符串转为时间戳的工具方法
    public static String parseIso8601ToTimestamp(String isoTime) {
        if (isoTime == null || isoTime.isEmpty()) {
            return String.valueOf(System.currentTimeMillis());
        }
        try {
            // 华为云格式：20250924T095916Z
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
            LocalDateTime localDateTime = LocalDateTime.parse(isoTime, formatter);
            ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneOffset.UTC);
            return String.valueOf(zonedDateTime.toInstant().toEpochMilli());
        } catch (Exception e) {
            // 解析失败，返回当前时间戳
            return String.valueOf(System.currentTimeMillis());
        }
    }

}